package com.rpc.core.holder.bean;


import com.rpc.core.param.RpcParams;
import com.rpc.core.holder.ImportParamHolder;
import com.rpc.core.holder.rag.RegInfoEnhancer;
import com.rpc.core.holder.rag.RegInfoHolder;
import com.rpc.core.holder.transmit.Request;
import com.rpc.core.holder.transmit.RequestSync;
import com.rpc.core.holder.transmit.Response;
import com.rpc.core.loadbalance.LoadBalance;
import com.rpc.core.remoting.Client;
import org.springframework.context.ApplicationContext;


public class ImportBean implements Bean {

    private RegInfoHolder holder;

    private static Object requestFail = new Object();

    private ApplicationContext context;

    private String itag;

    private LoadBalance lbBean;

    private RpcParams params;


    public ImportBean(RegInfoHolder infoHolder, ApplicationContext context, ImportParamHolder paramHolder) {
        this.holder = infoHolder;
        this.context = context;
        this.itag = paramHolder.getItag();
        this.params = context.getBean(RpcParams.class);

        Object bean = context.getBean(paramHolder.getLb());
        if (!(bean instanceof LoadBalance)) {
            throw new RuntimeException("import bean build exception");
        }

        if (!paramHolder.isLazy()) {
            startAllClient();
        }

        this.lbBean = (LoadBalance) bean;
    }

    private void startAllClient() {
        this.holder.getEnInfos().forEach(RegInfoEnhancer::getClient);
    }


    @Override
    public Object invoke(String methodName, Object[] args) throws Throwable {

        int count = params.getFailRetryCount();

        for (int i = 0; i < count; i++) {
            //选出一个要调用的目标
            Request request = buildRequest(itag + "#" + methodName, args);
            RegInfoEnhancer enhancer = lbBean.get(holder.getEnInfos());
            Client client = enhancer.getClient();
            if (client == null) {
                throw new RuntimeException(itag + " is no client to use");
            }

            Object result = sendRequest(client, request);

            if (result != requestFail) {
                return result;
            }
            // 请求失败处理,关闭之前的
            enhancer.close();
        }

        throw new RuntimeException(itag + " call fail!");

    }

    private Object sendRequest(Client client, Request request) throws Throwable {

        RequestSync sync = new RequestSync(client);
        Response response = sync.send(request, params.getTimeout(), params.getTimeUnit());

        //请求超时
        if (response == null) {
            return requestFail;
        }

        if (response.isInvokeSuccess()) {
            return response.getResult();
        }

        throw response.getThrowable();
    }

    private Request buildRequest(String key, Object[] args) {
        return new Request(-1, key, args);
    }

}
